﻿using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
using ClassLibrary;
using ObTookit.Auto;

namespace ObTookit
{
    /// <summary>
    /// 自动生成代码类
    /// =============
    /// 1.Info(Model),Qry(Query),Permit
    /// 2.DA(DAL),LG(BLL),Serv(Server)
    /// 3.Api(SDK)
    /// 4.ASPX,JS
    /// 5.Ctrl,View
    /// 6.SQL
    /// 7.Doc(Descri)
    /// </summary>
    public class AutoCoder
    {
        private string author = "";
        private string createDate = "";
        private AutoObject ao;
        private List<FieldObject> fos;

        public AutoCoder(AutoObject ao, DataTable dt)
        {
            this.ao = ao;
            fos = DataTableToFieldObject(dt);
            this.author = System.Environment.UserName;
            this.createDate = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }

        /// <summary>
        /// 表字段转换为字段实体类
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public List<FieldObject> DataTableToFieldObject(DataTable dt)
        {
            List<FieldObject> list = new List<FieldObject>();
            foreach (DataRow dr in dt.Rows)
            {
                #region 获取表字段属性语句

                /*
                 * "USE {1};
                 * SELECT
                 * [Sort]=a.colorder,
                 * [Name]=a.name,
                 * [IsPKey]=case when exists(SELECT 1 FROM sysobjects where xtype='PK' and name in (
                 *  SELECT name FROM sysindexes WHERE indid in(
                 *      SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid
                 * ))) then 1 else 0 end,
                 * [IsIdentity]=case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then 1 else 0 end,
                 * [Type]=b.name,
                 * [Bytes]=a.length,
                 * [Length]=COLUMNPROPERTY(a.id,a.name,'PRECISION'),
                 * [Digits]=ISNULL(COLUMNPROPERTY(a.id,a.name,'Scale'),0),
                 * [Nullable]= a.isnullable ,
                 * [DefValue]=ISNULL(e.text,'')
                 * FROM syscolumns a LEFT JOIN systypes b ON a.xusertype=b.xusertype INNER JOIN sysobjects d ON a.id=d.id
                 * AND d.xtype='U' AND d.name !='dtproperties' LEFT JOIN syscomments e ON a.cdefault=e.id
                 * WHERE d.name='{0}' ORDER BY a.id,a.colorder"
                 */

                #endregion 获取表字段属性语句

                int sort = 0;
                int.TryParse(dr["Sort"].ToString(), out sort);
                string name = dr["Name"].ToString();
                int isPKey = 0;
                int.TryParse(dr["IsPKey"].ToString(), out isPKey);
                int isIdentity = 0;
                int.TryParse(dr["IsIdentity"].ToString(), out isIdentity);
                string type = dr["Type"].ToString();
                int bytes = 0;
                int.TryParse(dr["Bytes"].ToString(), out bytes);
                int length = 0;
                int.TryParse(dr["Length"].ToString(), out length);
                int digits = 0;
                int.TryParse(dr["Digits"].ToString(), out digits);
                bool nullable = false;
                bool.TryParse(dr["Nullable"].ToString(), out nullable);
                string defValue = dr["DefValue"].ToString();
                string descr = dr["Descr"].ToString();

                FieldObject fo = new FieldObject();
                fo.Sort = sort;
                fo.Name = name;
                fo.PrimaryKey = (isPKey == 1);
                if(fo.PrimaryKey)
                {
                    ao.IdName = fo.Name;    //设置主键名称
                }
                fo.Identity = (isIdentity == 1);
                fo.DbType = type;
                fo.Type = DbTypeToObType(type);
                fo.Bytes = bytes;
                fo.Length = length;
                fo.Digits = digits;
                fo.Nullable = nullable;
                fo.DefaultValue = defValue;
                fo.Descr = descr;
                //
                string split = "_";
                fo.Alias = (name.Length > 2)
                    ? StringUtil.FristLower(name, split)
                    : name.ToLower();  //（别名：去掉"_"，，首字母小写；数据库字段命名最好采用驼峰法）
                fo.PrivateProp = (name.Length > 2)
                    ? StringUtil.FristLower(name, split)
                    : name.ToLower();    //（私有字段：去掉"_"，首字母小写；数据库字段命名最好采用驼峰法）
                fo.PublicProp = StringUtil.FirstUpper(name, '_'); //（公有属性：去掉'_'，首字母大写）

                list.Add(fo);
            }
            return list;
        }

        /// <summary>
        /// 数据库类型转换为Obsidian自定义数据类型
        ///
        /// 除了ListField，EnumField之外的基本Field类型
        ///     IntListField
        ///     LongListField
        ///     BoolListField
        ///     StringListField
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        public string DbTypeToObType(string dbType)
        {
            string obType = "";
            switch (dbType.ToLower())
            {
                case "int":
                case "smallint":
                case "tinyint":
                    obType = "IntField";
                    break;

                case "bigint":
                    obType = "LongField";
                    break;

                case "float":
                    //case "numeric":
                    //case "real":
                    obType = "DoubleField";
                    break;

                case "decimal":
                case "money":
                case "smallmoney":
                    obType = "DecimalField";
                    break;

                case "datetime":
                    obType = "DateTimeField";
                    break;

                case "bit":
                    obType = "BoolField";
                    break;

                case "char":    //max 8000单字节
                case "nchar":   //max 4000双字节
                case "varchar":
                case "nvarchar":
                case "text":
                case "ntext":
                    obType = "StringField";
                    break;

                default:
                    obType = "StringField";
                    break;
            }
            return obType;
        }

        #region 自动生成代码

        public string CreateInfo()
        {
            InfoCoder coder = new InfoCoder();
            coder.Template = "Info.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        public string CreateQry()
        {
            QryCoder coder = new QryCoder();
            coder.Template = "Qry.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        public string CreatePermit()
        {
            PermitCoder coder = new PermitCoder();
            coder.Template = "Permit.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        /************/

        public string CreateDA()
        {
            DACoder coder = new DACoder();
            coder.Template = "DA.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        public string CreateLG()
        {
            LGCoder coder = new LGCoder();
            coder.Template = "LG.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        public string CreateServ()
        {
            ServCoder coder = new ServCoder();
            coder.Template = "Serv.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        /************/

        public string CreateApi()
        {
            ApiCoder coder = new ApiCoder();
            coder.Template = "Api.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        /************/

        public string CreateAspx()
        {
            AspxCoder coder = new AspxCoder();
            coder.Template = "Aspx.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        public string CreateJs()
        {
            JsCoder coder = new JsCoder();
            coder.Template = "Js.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        /************/

        public string CreateCtrl()
        {
            CtrlCoder coder = new CtrlCoder();
            coder.Template = "Ctrl.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        public string CreateView()
        {
            ViewCoder coder = new ViewCoder();
            coder.Template = "View.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        /************/

        public string CreateSQL()
        {
            SQLCoder coder = new SQLCoder();
            coder.Template = "SQL.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        /************/

        public string CreateDoc()
        {
            DocCoder coder = new DocCoder();
            coder.Template = "Doc.tpl";
            coder.Author = author;
            coder.CreateDate = createDate;
            coder.AutoObj = ao;
            coder.FieldObjs = fos;
            return coder.CreateCode();
        }

        /************/

        #endregion 自动生成代码

        #region 读取模板文件
        private string ReadTemplate(string fileName)
        {
            string filePath = System.AppDomain.CurrentDomain.BaseDirectory;
            filePath = filePath + "Template/" + fileName;
            if (!File.Exists(filePath))
            {
                return null;
            }
            string text = File.ReadAllText(filePath, System.Text.Encoding.Default);
            return text;
        }
        #endregion
    }
}